##
## PlanetfallSpellsInterface
## Provides a central point of entrance for functions relating to spells.
##

import CvUtil
from CvPythonExtensions import *
import PlanetfallSpells
import PlanetfallSpellsPlotSelectScreen
import PlanetfallSpellsEntitySelectScreen

# globals
gc = CyGlobalContext()

PLANETFALL_SPELL_PLOT_LAYER = 2

# Used in case there was a spell that was in targetting mode
# while the python files were being reloaded (a common occurance
# in debugging spells). This makes sure that we set the interface
# mode back to normal. Screens will also close, and those gaurds
# are located in their respective files.
if CyInterface().getInterfaceMode() == InterfaceModeTypes.INTERFACEMODE_SPELL:
    gc.setLocalInterfaceMode(InterfaceModeTypes.INTERFACEMODE_SELECTION)

#################################################################################################
# Spellbook dictionary
# Stores the singleton object for each spell type.
#################################################################################################
gSpellbook = {}

def getSpellbook():
    global gSpellbook
    # Makes sure that the files are loaded. This should only need to happen
    # once, unless python files are reloaded.
    if (len(gSpellbook) == 0 and gc.getNumSpellInfos() > 0):
        for iSpell in range(gc.getNumSpellInfos()):
            CvUtil.pyPrint("Adding spell %i to spellbook" % iSpell)
            # Gets the info on where to find the spell
            szFilename = gc.getSpellInfo(iSpell).getSpellFilename()
            szClassName = gc.getSpellInfo(iSpell).getSpellClass()

            # Load up the file as a module, then use this to call the constructor
            mModule = __import__(szFilename)
            CvUtil.pyPrint("mModule.%s(%d)" % (szClassName, iSpell))
            gSpellbook[iSpell] = eval("mModule.%s()" % szClassName)
            gSpellbook[iSpell].setSpellNumber(iSpell)

            # Now let's make sure all of the functions that need overriding are overridden.
            pAbstractFunctions = gSpellbook[iSpell].getAbstractFunctions()

            if pAbstractFunctions is None:
                CvUtil.pyAssert(false, "Warning: The spell base class you are using returned nothing for abstract classes. It is probably corrupt. See the maker of the base class you're trying to use.")
            else:
                for szFunctionName in pAbstractFunctions:
                    # If we were successfully able to get the attribute, then that means the function
                    # was never overridden.
                    try:
                        fakeVariable = eval("gSpellbook[iSpell].%s.__ABSTRACT__" % szFunctionName)
                        CvUtil.pyAssert(False, "Warning: Required function %s is not implemented in spell class %s" % (szFunctionName, szClassName))
                    except:
                        pass

                    
    return gSpellbook


#################################################################################################
# Functions that are called from the SDK, passed along to the correct spell to recieve a value
# or do an action.
#
#################################################################################################

def canGroupCast(argsList):
    eSpell, pCastingGroup, pCastingPlot, bVisible = argsList
    pSpellbook = getSpellbook()
    return pSpellbook[eSpell].canGroupCast(pCastingGroup, pCastingPlot, bVisible)

def handleActionButtonClick(argsList):
    eSpell, pSelectionGroup, pCastingPlot, bAlt, bShift, bCtrl = argsList

    # Set what the current spell is. This function is only called on the local computer
    # so we don't need to make a multiplayer check.
    setCurrentSpellValue(eSpell)
    pSpellbook = getSpellbook()
    
    return pSpellbook[eSpell].onSpellActivate(pSelectionGroup, pCastingPlot)

def onPlotHover( pCastingGroup, pCastingPlot, pHoverPlot ):
    CyEngine().clearColoredPlots( PLANETFALL_SPELL_PLOT_LAYER )
    getCurrentSpell().onPlotHover( pCastingGroup, pCastingPlot, pHoverPlot )

def onPlotSelect( pCastingGroup, pCastingPlot, pTargetPlot ):
    getCurrentSpell().onPlotSelect( pCastingGroup, pCastingPlot, pTargetPlot )
    
def parseTargetInfo(argsList):
    iEntityRow, iItemNumber, bStrategyText = argsList
    pEntitySelectScreen = getEntitySelectScreen()

    retString = pEntitySelectScreen.getEntityHelpText(iEntityRow, iItemNumber)
    if retString:
        return retString.encode("utf8", "replace")

def executeTargetInfo(argsList):
    iEntityRow, iItemNumber, bStrategyText = argsList
    pEntitySelectScreen = getEntitySelectScreen()

    pEntitySelectScreen.executeTargetInfo(iEntityRow, iItemNumber)

def onEntitySelect(pCastingGroup, pCastingPlot, pEntitySelected):
    pEntitySelectScreen = getEntitySelectScreen()
    pEntitySelectScreen.hideScreen()
    getCurrentSpell().onEntitySelect( pCastingGroup, pCastingPlot, pEntitySelected )

# This function called on all computers.
def startSpellResults(argsList):
    eSpell, pGroup, iData1, iData2, iFlags = argsList

    # Reset the spell being cast if the spell is being cast for the local player.
    if (pGroup.getOwner() == gc.getGame().getActivePlayer()):
        clearCurrentSpellValue()

    return getSpellbook()[eSpell].startSpellResults(pGroup, (iData1, iData2, iFlags) )

# This function called on all computers.
def continueSpellResults(argsList):
    eSpell, pGroup, iData1, iData2, iData3 = argsList
    return getSpellbook()[eSpell].continueSpellMission(pGroup, (iData1, iData2, iData3) )

def cleanupSpell(argsList):
    eSpell, pGroup, iData1, iData2, iData3 = argsList
    getSpellbook()[eSpell].cleanupSpell(pGroup, (iData1, iData2, iData3) )
    
    

# This function is called on all computers.
def getUnitHelpText(argsList):
    eSpell, pUnit = argsList
    pSpellbook = getSpellbook()

    retString = pSpellbook[eSpell].getUnitHelpText(pUnit)
    if retString:
        return retString.encode("utf8", "replace")



#################################################################################################
# Stores the number of the spell that is currently being casted (looking
# for a pie menu or plot target). Note that this is only for the local computer.
# Also, stores the plot that has been selected, as well as the "secondary target",
# which is a 3-tuple of the iData1, iData2, iData3
##################################################################################################
g_eCurrentSpell = -1
g_pPlotTarget = None
g_pSecondaryTarget = None

def getCurrentSpellValue():
    return g_eCurrentSpell

def setCurrentSpellValue( eNewSpell ):
    global g_eCurrentSpell
    g_eCurrentSpell = eNewSpell
    setLocalInterfaceModeToSpell()
    gc.setLocalSpell( eNewSpell )


def clearCurrentSpellValue():
    global g_eCurrentSpell
    g_eCurrentSpell = -1
    resetLocalInterfaceMode()
    gc.setLocalSpell( SpellTypes.NO_SPELL )

def getCurrentPlotTarget():
    return g_pPlotTarget

def setCurrentPlotTarget(pPlot):
    global g_pPlotTarget
    g_pPlotTarget = pPlot

def clearCurrentPlotTarget():
    global g_pPlotTarget
    g_pPlotTarget = None

def getSecondaryTarget():
    return g_pSecondaryTarget

def setSecondaryTarget(pSecondaryTarget):
    global g_pSecondaryTarget
    g_pSecondaryTarget = pSecondaryTarget

def clearCurrentPlotTarget():
    global g_pPlotTarget
    g_pPlotTarget = None
    
def getCurrentSpell():
    pSpellbook = getSpellbook()
    if (g_eCurrentSpell in pSpellbook):
        return pSpellbook[g_eCurrentSpell]
    else:
        return None



#################################################################################################
# The screens used for default plot and pie menu choosers.
#
#################################################################################################
g_ePlotSelectScreenName = "PlanetfallSpellsPlotSelectScreen"
g_ePlotSelectScreenEnum = 155
g_pPlotSelectScreen = PlanetfallSpellsPlotSelectScreen.PlanetfallSpellsPlotSelectScreen()

def getPlotSelectScreenEnum():
    return g_ePlotSelectScreenEnum

def getPlotSelectScreenName():
    return g_ePlotSelectScreenName

def getPlotSelectScreen():
    return g_pPlotSelectScreen

def showPlotSelectScreen( pCastingGroup, pCastingPlot ):
    g_pPlotSelectScreen.interfaceScreen( pCastingGroup, pCastingPlot )

def hidePlotSelectScreen():
    g_pPlotSelectScreen.hideScreen()


g_eEntitySelectScreenName = "PlanetfallSpellsEntitySelectScreen"
g_eEntitySelectScreenEnum = 156
g_pEntitySelectScreen = PlanetfallSpellsEntitySelectScreen.PlanetfallSpellsEntitySelectScreen()

def getEntitySelectScreenName():
    return g_eEntitySelectScreenName

def getEntitySelectScreenEnum():
    return g_eEntitySelectScreenEnum

def getEntitySelectScreen():
    return g_pEntitySelectScreen

def showEntitySelectScreen(pCastingGroup, pCastingPlot, pTargetList, pRenderCallback):
    g_pEntitySelectScreen.interfaceScreen(pCastingGroup, pCastingPlot, pTargetList, pRenderCallback)

def hideEntitySelectScreen():
    g_pEntitySelectScreen.hideScreen()

def getScreenEnumsUsed():
    # TODO
    return [g_ePlotSelectScreenEnum, g_eEntitySelectScreenEnum]



#################################################################################################
# Functions called from the screens and screen utils to get the spells to do stuff.
#
#################################################################################################

def resetLocalInterfaceMode():
    print "Resetting local interface mode"
    gc.setLocalInterfaceMode(InterfaceModeTypes.INTERFACEMODE_SELECTION)

def setLocalInterfaceModeToSpell():
    print "Setting local interface mode to spell."
    gc.setLocalInterfaceMode(InterfaceModeTypes.INTERFACEMODE_SPELL)

def redrawPlots():
    pCurrentSpell = getCurrentSpell()
    if pCurrentSpell:
        pCurrentSpell.redrawPlots()

def onNewPlotHighlighted():
    pCurrentSpell = getCurrentSpell()
    if pCurrentSpell:
        pCurrentSpell.onNewPlotHighlighted( CyInterface().getMouseOverPlot() )

def onGameUpdate():
    pCurrentSpell = getCurrentSpell()
    if pCurrentSpell:
        pCurrentSpell.onGameUpdate()

def cancelSpell( pCastingGroup, pCastingPlot ):
    hidePlotSelectScreen()
    hideEntitySelectScreen()
    clearCurrentSpellValue()
    CyEngine().clearColoredPlots( PLANETFALL_SPELL_PLOT_LAYER )
    
    


#################################################################################################
# Tells the screen what layer to use when coloring plots.
#
#################################################################################################
g_ColoredPlotLayer = 2
def getColoredPlotLayer():
    return g_ColoredPlotLayer




#################################################################################################
# Utility Functions
#
#################################################################################################

# Since there is no c++ call to get the current interface mode, I need to
# call a python function to do it for me. This function is called from C++.
def getInterfaceMode():
    return CyInterface().getInterfaceMode()


